//
//  HollyPhoneManager.m
//  hollyphone
//
//  Created by hollycrm on 2023/3/11.
//

#import "HollyPhoneManager.h"
#import "wrapper.h"
#import "LogManager.h"
#import "CallOutViewController.h"
#import "Common.h"
#import "HollyPhoneProtocol.h"
#import "FloatingViewController.h"
#import "Request.h"
#import "InitViewController.h"
#import "Utils.h"
#import <AVFAudio/AVAudioSession.h>
#import <AVFoundation/AVFoundation.h>
#import "AudioHelper.h"
#import "AudioManager.h"
#import "HollyPhoneSdk.h"
#import "SimplePing.h"
#import "STDPingServices.h"
#define urlFor1139 @"HollyPhoneFor1139"
#define HollyPhoneDeviceId @"HollyPhoneDeviceId"
#define callServiceOverTime 10

HollyPhoneManager  *mptr = nil ;
@interface HollyPhoneManager()<SimplePingDelegate>{
 NSString *pbxIp;
 NSString *pbxPort;
 NSString *pbxNo;
 NSString *pbxPwd;
 NSTimer *timer;
 NSTimer *callTimer;
 UIWindow *floatWindow;
 InitViewController *initview;
 void(^succ)(NSString*) ;
 void(^fail)(NSString*) ;
 NSMutableDictionary *urlMap;
 UIImage *backgroundimage;
 SimplePing *ping;
 NSDate *pingStartTime;
 BOOL loop_ping ;
 NSTimer *netTimer;
 
 int sendCount;
 int receiveCount;
 int lossCount;
 NSTimeInterval pingtime;
 double pingLoss;
 
 BOOL pinging;
 
 int pingIndex;
 
 NSMutableArray *pingGroup;
 
 NSString *pingserver;
 
 NSDictionary *params;
 
 BOOL initing;
 
 NSString *temppbxserver;
 
}
@property(atomic,assign) NSDate* lastCalltime;
@property(nonatomic, strong) STDPingServices    *pingServices;

@end
@implementation HollyPhoneManager
+ (instancetype)shareManager{
 static HollyPhoneManager * manager = nil;
 static dispatch_once_t onceToken = 0;
 dispatch_once(&onceToken, ^{
  manager = [[super allocWithZone:NULL] init];
  mptr = manager;
  manager.phoneStatus = [PhoneStatus new];
  manager.phoneStatus.params = [manager createDefaultSipHeader:[NSDictionary new]];
  [manager initFloatWindow];
  [manager initWrapper];
  [manager setUniqueId];
  
  manager->urlMap  = [[NSMutableDictionary alloc] init];
  manager->pingserver = @"www.baidu.com";
  [NSNotificationCenter.defaultCenter addObserver:manager
                                         selector:@selector(audioRouteChangeListenerCallback:)
                                             name:AVAudioSessionRouteChangeNotification
                                           object:[AVAudioSession sharedInstance]];
  
  [NSNotificationCenter.defaultCenter addObserver:manager selector:@selector(handleSilenceSecondaryAudioHintNotification:) name:AVAudioSessionSilenceSecondaryAudioHintNotification object:nil];
  
  [[NSNotificationCenter defaultCenter] addObserver:manager selector:@selector(audioSessionInterruptionNotification:) name:AVAudioSessionInterruptionNotification object:nil];
  
 });
 return manager;
}

- (void)audioSessionShouldResume:(NSNotification *)noti {
 
}

- (void)audioSessionInterruptionNotification:(NSNotification *)noti {
 NSInteger InterruptionType = [[noti.userInfo objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
 NSLog(@"***********************");
 switch (InterruptionType) {
  case AVAudioSessionInterruptionTypeBegan: {
   NSLog(@"开始打断");
   [[CPPWrapper new] pauseCall];
   self.phoneStatus.interrupt = true;
   self.phoneStatus.mediaState = 0;
  }
   break;
  case AVAudioSessionInterruptionTypeEnded: {
   NSLog(@"结束打断");
   
   [[CPPWrapper new] restoreCall];
   
  }
   break;
 
  default:
   break;
 }
 
}





- (void)restoreCall{
 [[CPPWrapper new] outgoingServiceCallWrapper:[HollyPhoneManager shareManager].phoneStatus.callId withIp:[HollyPhoneManager shareManager].phoneStatus.ip andPort:[HollyPhoneManager shareManager].phoneStatus.port andPhoneNum:[HollyPhoneManager shareManager].phoneStatus.fromNum andParams:[HollyPhoneManager shareManager].phoneStatus.params];
 self.phoneStatus.interrupt = false;
}

- (void)handleSilenceSecondaryAudioHintNotification:(NSNotification *)notification {
 NSNumber *type = notification.userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey];
 if ([type intValue] == AVAudioSessionSilenceSecondaryAudioHintTypeBegin) {
  NSLog(@"Other app has started using the microphone");
  
  // Handle the case when another app starts using the microphone
 } else if ([type intValue] == AVAudioSessionSilenceSecondaryAudioHintTypeEnd) {
  NSLog(@"Other app has stopped using the microphone");
  
  // Handle the case when another app stops using the microphone
 }
}

- (void)setUniqueId{
 self.managerId =[NSString stringWithFormat:@"%@-%@",[Utils generateUUIDString],[Utils currentDateStringWithFormat:@"yyyy-MM-dd HH:mm:ss"]] ;
 NSString *did = [Utils readValueWithKey: HollyPhoneDeviceId];
 if([did isEqualToString:@""]){
  self.deviceId = [Utils generateUUIDString];
  [Utils saveValue:self.deviceId withKey:HollyPhoneDeviceId];
 }
 else{
  self.deviceId = did;
 }
}

- (void)audioRouteChangeListenerCallback:(NSNotification *)notif {
 NSInteger  reason = [[notif.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
 if (reason ==
     AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
  [self enableBluetooth:false];
  return;
 }
  
 AVAudioSessionRouteDescription *newRoute = [AVAudioSession sharedInstance].currentRoute;
 
 if (newRoute) {
  if (newRoute.outputs.count == 0){
   return;
  }
  NSString *route = newRoute.outputs[0].portType;
  
  if (([[AudioHelper bluetoothRoutes] containsObject:route])) {
   [self enableBluetooth:true];
  } else {
   [self enableBluetooth:false];
  }
 }
}




-(void)initWrapper{
 [[CPPWrapper new] createLibWrapper];
 [[CPPWrapper new]  log_writer_wrapper:logWriter];
 [[CPPWrapper new] im_receiver_wrapper:imReceiver];
 [[CPPWrapper new] call_listener_wrapper:callStatus];
 [[CPPWrapper new] incoming_call_wrapper:callIn];
 [[CPPWrapper new] callmedia_state_wrapper:callMediaState];
 //    if (self.wrapper == nil){
 //        self.wrapper = [CPPWrapper new];
 //        [self.wrapper createLibWrapper];
 //        [self.wrapper log_writer_wrapper:logWriter];
 //     [self.wrapper im_receiver_wrapper:imReceiver];
 //        [self.wrapper call_listener_wrapper:callStatus];
 //        [self.wrapper incoming_call_wrapper:callIn];
 //    }
}

-(void)sendState{
 
 [[CPPWrapper new] sendOptions];
 
 bool mediaok = self.phoneStatus.mediaState == 1 && !self.phoneStatus.interrupt;
 
 NSString *msg = [NSString stringWithFormat:@"mic[%d],%@",mediaok,self.phoneStatus.pingstr];
 
 //[[CPPWrapper new] sendMessage:msg]; //临时去掉吧，后台javaforce 没处理这个
 self.phoneStatus.mediaState = 1;
}

void callMediaState(int state){
 NSLog(@"%@", [NSString stringWithFormat:@"callmediastate--------------%d",state]);
 [mptr callMediaState:state];
}

-(void)callMediaState:(int)state{
 self.phoneStatus.mediaState = state;
}

-(void)unregister{
 [self stopPingSipServer];
 if ([[CPPWrapper new] registerStateInfoWrapper]){
  if(self.phoneStatus.inCall){
   [[CPPWrapper new] hangupCallWrapper];
  }
  [[CPPWrapper new] unregisterAccountWrapper];
 }
 else if(self->_phoneStatus.serviceCallMode){
  
 }
}

-(void)enableBluetooth:(Boolean)enable{
 if (enable){
  NSError *err = nil;
  AVAudioSessionPortDescription *_bluetoothPort = [AudioHelper bluetoothAudioDevice];
  [[AVAudioSession sharedInstance] setPreferredInput:_bluetoothPort error:&err];
  if (err){
   if([AudioManager shared]._isSpeakerOn){
    [[AudioManager shared] setSpeakerOn];
   }
   else{
    [[AudioManager shared] setSpeakerOff];
   }
  }
 }
 else{
  if([AudioManager shared]._isSpeakerOn){
   [[AudioManager shared] setSpeakerOn];
  }
  else{
   [[AudioManager shared] setSpeakerOff];
  }
 }
}

//检测到服务器延迟

-(void)initPing{
 [self clearPing];
 ping = [[SimplePing alloc] initWithHostName:@"a6ha-zczy.7x24cc.com"];
 ping.delegate = self;
}

-(void)startNetMonitor{
 [self stopNetMonitor];
 self->netTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(newPingSipServer) userInfo:nil repeats:YES];
 [self->netTimer fire];
}

-(void)stopNetMonitor{
 if(self->netTimer != nil){
  [self->netTimer invalidate];
  self->netTimer = nil;
 }
}

-(void)newPingSipServer{
 
 if(pinging){
  return;
 }
 pinging = true;
 [self sendState];
 self.pingServices = [STDPingServices startPingAddress:pingserver callbackHandler:^(STDPingItem *pingItem, NSArray *pingItems) {
  if (pingItem.status != STDPingStatusFinished) {
   
  } else {
   NSDictionary *result = [STDPingItem analysisPingResult:pingItems];
   int allCount = [[result objectForKey:@"all"] intValue];
   int rCount = [[result objectForKey:@"receive"] intValue];
   CGFloat lossPercent = (CGFloat)(allCount - rCount) / MAX(1.0, allCount) * 100;
   if(allCount == 0 && rCount == 0){
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:BadNetWork object:nil]];
    self.phoneStatus.pingstr =[NSString stringWithFormat:@"ping%@===>bad",[Utils currentDateStringWithFormat:@"HH:mm:ss"]] ;
   }
   if( lossPercent > 30.0 ){
    //NSLog(@"----------------highLossRate:%f,,result:%f",lossPercent,lossPercent-30.0);
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:BadNetWork object:nil]];
    self.phoneStatus.pingstr =[NSString stringWithFormat:@"ping%@===>bad",[Utils currentDateStringWithFormat:@"HH:mm:ss"]] ;
   }
   else{
    //NSLog(@"**************send:%d*****receive:%d",allCount,receivedCount);
    self.phoneStatus.pingstr =[NSString stringWithFormat:@"ping%@===>good",[Utils currentDateStringWithFormat:@"HH:mm:ss"]] ;
   }
   self->pinging = false;
  }
 }];
}

-(void)startPingSipServer{
 [self startNetMonitor];
 
 return;
 loop_ping = true;
 pinging = false;
 [self resetPingData];
 [self loopPing];
 [self startNetMonitor];
 
}

-(void)resetPingData{
 sendCount = 0;
 receiveCount = 0;
 lossCount = 0;
 pingtime = 0;
 pingLoss = 0;
}

-(void)loopPing{
 @synchronized (self) {
  if(loop_ping){
   if(!pinging){
    [self startTimeOutTimer];
    [self initPing];
    pinging = true;
    [self->ping start];
    
   }
  }
 }
 
}

-(void)startTimeOutTimer{
 
 [self performSelector:@selector(timeout:) withObject:[NSNumber numberWithInt:pingIndex] afterDelay:2];
 
}

-(void)timeout:(NSNumber*)index{
 @synchronized (self) {
  if(self->ping != nil && ([index isEqualToNumber:[NSNumber numberWithInt:pingIndex]])){
   NSLog(@"timeout-------------");
   [self pingEnd:false];
  }
 }
 
}

-(void)pingEnd:(Boolean)succ{
 @synchronized (self) {
  pingIndex ++;
  if(ping != nil){
   [self clearPing];
   if (succ){
    receiveCount = receiveCount + 1;
    
   }
   else{
    lossCount = lossCount + 1;
   }
   pinging = false;
   [self loopPing];
  }
  
 }
}

-(void)clearPing{
 if (ping != nil){
  [ping stop];
  ping = nil;
 }
}

//停止检测到服务器延迟
-(void)stopPingSipServer{
 [self.pingServices cancel];
 [self stopNetMonitor];
 return;
 
 loop_ping = false;
 [self clearPing];
 [self stopNetMonitor];
}

- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address {
 //NSLog(@"pinging %@", pinger.hostName);
 [pinger sendPingWithData:nil];
 sendCount ++;
}

- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error{
 // NSLog(@"ping faile with error : %@",error.description);
 [self pingEnd:false];
}

-(void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error{
 // NSLog(@"ping faile with error : %@",error.description);
 [self pingEnd:false];
}

-(void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet{
 //NSLog(@"ping unexpectedPacket");
 [self pingEnd:false];
}

- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber {
 pingStartTime = [NSDate date];
}

- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber {
 //NSLog(@"ping didReceivePingResponsePacket");
 NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:pingStartTime];
 //NSLog(@"response from %@: %f ms----loss-rate: %f", pinger.hostName, elapsedTime * 1000,(CGFloat)(self.sendCount - self.receiveCount) / (CGFloat)self.sendCount);
 pingtime = elapsedTime * 1000;
 
 receiveCount ++;
 
 [self pingEnd:true];
}

//定时任务检测注册状态
-(void)startRegisteStateCheck{
 
 if (timer != nil){
  [self stopRegisterCheck];
 }
 timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) {
  if(self->_phoneStatus.registered != [[CPPWrapper new] registerStateInfoWrapper]){
   self->_phoneStatus.registered = [[CPPWrapper new] registerStateInfoWrapper];
   [NSNotificationCenter.defaultCenter postNotificationName:hollyPhoneRegStateChange object:@{@"regState":[NSNumber numberWithBool:self->_phoneStatus.registered]}];
   
   if([[CPPWrapper new] registerStateInfoWrapper]){
    self->succ(@"init succeed");
    self->_phoneStatus.registered = true;
    if (![self.phoneStatus.phoneNum isEqualToString:@""] && !self.phoneStatus.inCall ){
     dispatch_async(dispatch_get_main_queue(), ^{
      [self->initview dismissViewControllerAnimated:false completion:^{
       [self callOut:self.phoneStatus.phoneNum];
      }];
      
      [self startCallTimer];
     });
    }
    
   }
   else{
    
   }
   
  }
 }];
 [timer fire];
}

-(void)stopCallTimer{
 if (callTimer != nil){
  [callTimer invalidate];
  callTimer = nil;
 }
}


-(void)startCallTimer{
 if (callTimer != nil){
  [self stopCallTimer];
 }
 
 callTimer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:true block:^(NSTimer * _Nonnull timer) {
  if (self->_phoneStatus.registered){
   self->_phoneStatus.callSeconds += 1;
   
   if(self->_phoneStatus.serviceCallMode && !self->_phoneStatus.callConected && self->_phoneStatus.callSeconds > callServiceOverTime){
    [Utils saveValue:@"" withKey:urlFor1139];
    [self unregister];
   }
   
   [NSNotificationCenter.defaultCenter postNotificationName:hollyPhoneCallTimeChange object:nil];
  }
 }];
 [timer fire];
}

-(void)stopRegisterCheck{
 if (timer != nil){
  [timer invalidate];
  timer = nil;
 }
}

-(void)initFloatWindow{
 self->floatWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 200, 86, 70)];
 self->floatWindow.layer.masksToBounds = true;
 self->floatWindow.windowLevel = 9999;
 FloatingViewController *floatController = [[FloatingViewController alloc] init];
 self->floatWindow.rootViewController = floatController;
 [floatController addGestrueRecongnizer:floatWindow];
 [floatWindow setHidden:true];
 
 if (@available(iOS 13.0, *)) {
  for (UIWindowScene *windowScene in [UIApplication sharedApplication].connectedScenes) {
   if (windowScene.activationState == UISceneActivationStateForegroundActive) {
    floatWindow.windowScene = windowScene;
    break;
   }
  }
 }
 
 //  self.phoneStatus.addObserver(self, forKeyPath: "content", options: NSKeyValueObservingOptions.new, context: nil)
 [self.phoneStatus addObserver:self forKeyPath:@"background" options:NSKeyValueObservingOptionNew context:nil];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
 
 if(self->initview != nil){
  self->initview.view.hidden = true;
  [self->initview removeFromParentViewController];
  self->initview = nil;
 }
 [floatWindow setHidden:!self.phoneStatus.background];
}

- (void)dealloc{
 [[NSNotificationCenter defaultCenter] removeObserver:self];
 [self.phoneStatus removeObserver:self forKeyPath:@"background"];
 [self stopRegisterCheck];
 [self stopCallTimer];
}

//let topVC = topMostController()
//let vcToPresent = vc.storyboard!.instantiateViewController(withIdentifier: "incomingCallVC") as! IncomingViewController
//vcToPresent.incomingCallId = CPPWrapper().incomingCallInfoWrapper()
//topVC.present(vcToPresent, animated: true, completion: nil)

//来电
void callIn(void){
 [mptr incomingCall];
}

-(void)incomingCall{
 dispatch_async(dispatch_get_main_queue(), ^{
  UIViewController * rootCon = [[Common new] topMostController];
  if (rootCon != nil){
   
  }
 });
}

//呼叫状态改变
void callStatus(int status){
 [mptr callStateChange:status];
}

-(void)callStateChange:(int)status{
 printf("****************%d", status);
 if(status == 1){
  self.phoneStatus.callConected = true;
 }
 if(self.phoneStatus.inCall){
  self.phoneStatus.callStatus = status;
  dispatch_async(dispatch_get_main_queue(), ^{
   UIViewController * rootCon = [[Common new] topMostController];
   
   if (rootCon != nil){
    if ([rootCon conformsToProtocol:@protocol(HollyPhoneProtocol)]){
     if ([rootCon respondsToSelector:@selector(callStatusChanged:)]){
      [rootCon performSelector:@selector(callStatusChanged:) withObject:[NSNumber numberWithInt:status]];
     }
    }
    if (status == 0){
     [self->floatWindow setHidden:true];
     [rootCon dismissViewControllerAnimated:false
                                 completion:^{
      [self unregister];
      [self stopRegisterCheck];
      [self stopCallTimer];
      [self.phoneStatus reset];
      
      
     }];
     
    }
   }
  });
 }
 else {
  
 }
}

//日志输出
void logWriter(int level,const char * buffer,int len){
 [mptr writeLog:level :buffer :len];
}

void imReceiver(const char * msg){
 [mptr  msgReceiver:msg];
}

-(void)msgReceiver:(const char *)msg{
 if (msg != nil){
  NSString *str = [[NSString alloc] initWithCString:msg encoding:NSUTF8StringEncoding];
  // NSLog(@"%@", str);
 }
}

-(void)writeLog:(int32_t)level :(const char *)buffer :(int32_t)len{
 if (buffer != nil){
  NSString *str = [[NSString alloc] initWithCString:buffer encoding:NSUTF8StringEncoding];
  [[LogManager sharedInstance] logInfo:@"" logStr:str];
 }
}
//注册状态监听

+ (id)allocWithZone:(struct _NSZone *)zone{
 return [self shareManager];
}

-(void)initUrl:(NSString *)accountName urlBack:(void(^)(NSString * message))success urlFail:(void(^)(NSString* message)) failed{
 
 NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
 [params setObject:accountName forKey:@"accountName"];
 Request *req = [[Request alloc] init];
 [req get:params withUrl:uap succ:^(NSDictionary * _Nonnull dic) {
  
  NSString *resultcode = [[dic valueForKey:@"errcode"] stringValue];
  
  if ([resultcode isEqualToString:@"0"]){
   //  https:// + a6.7x24cc.com + /commonInte
   NSString *domain = [[dic objectForKey:@"result"] objectForKey:@"domain"];
   if([domain isEqualToString:@""]){
    failed(@"error: empty address");
    return;
   }
   NSString *url =[NSString stringWithFormat:@"https://%@/commonInte",domain] ;
   success(url);
  }
  else{
   //obj["resultMsg"]
   NSString *errorMsg = [dic objectForKey:@"errmsg"];
   if(errorMsg != nil){
    failed([NSString stringWithFormat:@"request uap error---%@",errorMsg]);
   }
   else{
    failed(@"request uap error");
   }
  }
 } fail:^(NSString * _Nonnull msg) {
  failed(@"request uap failed");
 }];
}

-(void)capBgImage{
 UIViewController *currentvc = [[Common new] topMostController];
 UIView *currentView = currentvc.view;
 UIGraphicsBeginImageContext(currentView.bounds.size);     //currentView 当前的view  创建一个基于绘图的图形上下文并指定大小为当前视图的bounds
 [currentView.layer renderInContext:UIGraphicsGetCurrentContext()];//renderInContext呈现接受者及其子范围到指定的上下文
 self.bgImage = UIGraphicsGetImageFromCurrentImageContext();//返回一个基于当前图形上下文的图片
 UIGraphicsEndImageContext();//移除栈顶的基于当前位图的图形上下文
 
}

-(NSDictionary *)createDefaultSipHeader:(NSDictionary *)dic{
 NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"ios",@"platform",SDK_VERSION,@"sdkversion",self.deviceId,@"deviceId",self.managerId,@"mId",self.cId,@"cId", nil];
 if (dic != nil){
  [temp addEntriesFromDictionary:dic];
 }
 //祝军说后台asterisk sip协议不支持jsonstr??报错了
 //    NSData *data=[NSJSONSerialization dataWithJSONObject:temp options:NSJSONWritingPrettyPrinted error:nil];
 //           NSString *str=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
 //            NSLog(@"JsonStr:%@",str);
 NSMutableString *tempstr = [[NSMutableString alloc] initWithCapacity:0];
 for(int i=0; i<temp.allKeys.count;i++){
  NSString *key = temp.allKeys[i];
  NSString * value = [temp objectForKey:key];
  if([value isKindOfClass:[NSString class]]){
   [tempstr appendString:key];
   [tempstr appendString:@"="];
   [tempstr appendString:value];
   if(i != temp.allKeys.count - 1){
    [tempstr appendString:@","];
   }
  }
 }
 NSString *str = [NSString stringWithFormat:@"%@",tempstr];
 return [[NSDictionary alloc] initWithObjectsAndKeys:str,@"ServiceParameters", nil];
}

-(void)call:(NSDictionary *)param succ:(void(^)(NSString * message))success fail:(void(^)(NSString* message)) failed{
 
 NSDate *now = [NSDate date];
 
 if (_lastCalltime && fabs([now timeIntervalSinceDate:_lastCalltime]) < 2) {
  failed(@"too frequently call....");
 }
 else{
  _lastCalltime = now;
  if(self.phoneStatus.inCall){
   
   PhoneStatus *phone = [HollyPhoneManager shareManager].phoneStatus;
   [[[Common alloc] init] goToCallView:phone.callId with:phone.phoneNum isRestore:true];
   return;
  }
  
  [Utils checkMicrophoneAuthorizationStatus:^(Boolean ok) {
   if (ok){
    
    self->succ = success;
    self->fail = failed;
    if (self->_phoneStatus.registered && self->_phoneStatus.callStatus != 0){
     failed(@"hollyphone in use....");
     return;
    }
    
    //    let params: [String : Any] =  ["flag":"20","loginName":HCAFService.s()?.userinfo.loginName,"password":HCAFService.s()?.userinfo.passWord,"md5":"81f0e1f0-32df-11e3-a2e6-1d21429e5f46"]
    NSString *loginName = [param objectForKey:@"loginName"];
    NSString *password = [param objectForKey:@"password"];
    //NSString *url = [param objectForKey:@"url"];
    NSString *phoneNum = [param objectForKey:@"phoneNum"];
    NSDictionary *externalParams = [param objectForKey:@"externalParams"];
    if ([[Utils chechNull:loginName] isEqualToString:@""]){
     failed(@"params loginName empty....");
     return;
    }
    if ([[Utils chechNull:password] isEqualToString:@""]){
     failed(@"params password empty....");
     return;
    }
    if ([[Utils chechNull:phoneNum] isEqualToString:@""]){
     failed(@"params phoneNum empty....");
     return;
    }
    
    self.cId = [NSString stringWithFormat:@"%@-%@",[Utils generateUUIDString],[Utils currentDateStringWithFormat:@"yyyy-MM-dd HH:mm:ss"]];
    if (externalParams != nil){
     self.phoneStatus.params = [self createDefaultSipHeader:externalParams];
    }
    else {
     self.phoneStatus.params = [self createDefaultSipHeader:[NSDictionary new]];
    }
    
    NSString *accountName = [loginName componentsSeparatedByString:@"@"][1];
    [self initUrl:accountName urlBack:^(NSString *message) {
     self->_phoneStatus.phoneNum = phoneNum;
     Request *req = [[Request alloc] init];
     NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
     [params setObject:@"20" forKey:@"flag"];
     [params setObject:@"sdk" forKey:@"type"];
     [params setObject:loginName forKey:@"loginName"];
     [params setObject:password forKey:@"password"];
     [params setObject:@"81f0e1f0-32df-11e3-a2e6-1d21429e5f46" forKey:@"md5"];
     NSString *url = message;
     [req post:params withUrl:url succ:^(NSDictionary * _Nonnull dic) {
      NSString *resultCode = [dic objectForKey:@"resultCode"];
      
      if ([resultCode isEqualToString:@"0000"]){
       
       NSDictionary *result = [dic objectForKey:@"result"];
       if([result objectForKey:@"ClientDialoutDisable"] != nil){
        if([[result valueForKey:@"ClientDialoutDisable"] boolValue]){
         failed(@"暂未开启语音通话，请联系管理员");
         return;
        }
       }
       NSString *sipName = [result objectForKey:@"sipNo"];
       NSString *sipPwd = [result objectForKey:@"sipPassword"];
       NSString *pbx =[result objectForKey:@"standbyPbxExIp"];
       pbx = [Utils chechNull:pbx];
       if ([pbx isEqualToString:@""]){
        pbx = [result objectForKey:@"pbx"];
       }
       
       self->pbxIp = [pbx componentsSeparatedByString:@":"][0];
       self->pbxPort = [pbx componentsSeparatedByString:@":"][1];
       
       [[CPPWrapper new] createAccountWrapper:sipName :sipPwd :self->pbxIp :self->pbxPort];
       
       
       dispatch_async(dispatch_get_main_queue(), ^{
        self->initview = [[InitViewController alloc] init];
        [[Common new] goToInitView:self->initview];
       });
       
       [self startRegisteStateCheck];
       
      }
      else{
       //obj["resultMsg"]
       NSString *errorMsg = [dic objectForKey:@"resultMsg"];
       if(errorMsg != nil){
        failed([NSString stringWithFormat:@"request a6 sip info error---%@",errorMsg]);
       }
       else{
        failed(@"request a6 sip info error");
       }
      }
     } fail:^(NSString * _Nonnull msg) {
      failed(@"request a6 sip info failed");
     }];
    } urlFail:^(NSString *message) {
     self->fail(message);
    }];
    
   }
   else{
    failed(@"need auth");
   }
  }];
  
 }
 
}

//外呼
-(void)callOut:(NSString * )phoneNum{
 self.phoneStatus.callId = [NSString stringWithFormat:@"sip:9%@@%@:%@",phoneNum,self->pbxIp,self->pbxPort];
 self.phoneStatus.phoneNum = phoneNum;
 self.phoneStatus.inCall = true;
 pingserver = self->pbxIp;
 [self startPingSipServer];
 [[Common new] goToCallView:self.phoneStatus.callId with:self.phoneStatus.phoneNum isRestore:false];
}

-(void)testSucc:(void(^)(NSString * message))success fail:(void(^)(NSString* message)) failed{
 [self restoreCall];
 // [Utils saveValue:@"429.87.134.6:5072" withKey:[self getServiceUrlKey:@"9500000002"]];
 
 // self.phoneStatus.serviceCallMode = true;
 // dispatch_async(dispatch_get_main_queue(), ^{
 // [[Common new] goToCallInitView];
 // });
 //
 //
 // self->succ = success;
 // self->fail = failed;
 // self.phoneStatus.phoneNum = @"13248034441";
 // self.phoneStatus.fromNum = @"18995608053";
 // self.phoneStatus.inCall = false;
 // [self callServiceNumWithPbxUrl:@"49.4.8.197:6060"];
}

-(void)callServiceNumWithPbxUrl:(NSString *)pbxServer{
 
 if ([pbxServer componentsSeparatedByString:@":"].count == 2){
  if(self.phoneStatus.inCall){
   return;
  }
  dispatch_async(dispatch_get_main_queue(), ^{
   //sipServer __NSCFString * @"49.87.132.6:5072" 0x0000600001d9a670
   NSString *ip = [pbxServer componentsSeparatedByString:@":"][0];
   //NSString *ip = @"111.87.132.9";
   NSString *port = [pbxServer componentsSeparatedByString:@":"][1];
   self.phoneStatus.callId = [NSString stringWithFormat:@"sip:%@@%@:%@",self.phoneStatus.phoneNum,ip,port];
   self->pingserver = ip;
   self.phoneStatus.ip = ip;
   self.phoneStatus.port = port;
   self.phoneStatus.registered = true;
   [self startPingSipServer];
   [self initSuccess];
   self.phoneStatus.inCall = true;
   [self startCallTimer];
   self->succ(@"success");
   
  });
 }
 else{
  [Utils saveValue:@"" withKey:[self getServiceUrlKey:self.phoneStatus.phoneNum]];
  self->fail(@"request a6 sip info error->pbxserver");
 }
 
}

-(NSString*)getServiceUrlKey:(NSString*)serviceNo{
 return [NSString stringWithFormat:@"%@-%@",serviceNo,urlFor1139];
}

-(void)callServiceNum:(NSDictionary *)param logoImg:(nonnull UIImage *)img succ:(void(^)(NSString * message))success fail:(void(^)(NSString* message)) failed {
 NSDate *now = [NSDate date];
 if (_lastCalltime && fabs([now timeIntervalSinceDate:_lastCalltime]) < 2 ) {
  failed(@"too frequently calls....");
  return;
 }
 else if (self->initing){
  failed(@"Initializing ....");
  return;
 }
 else{
  _lastCalltime = now;
  if(self.phoneStatus.inCall){
   PhoneStatus *phone = [HollyPhoneManager shareManager].phoneStatus;
   [[[Common alloc] init] goToCallView:phone.callId with:phone.phoneNum isRestore:true];
   return;
  }
  [Utils checkMicrophoneAuthorizationStatus:^(Boolean ok) {
   if (ok){
    self->succ = success;
    self->fail = failed;
    self.logoImg = img;
    self->params = param;
    if(self.phoneStatus.inCall){
     failed(@"hollyphone in use....");
     return;
    }
    NSString *accountName = [param objectForKey:@"accountName"];
    NSString *serviceNumber = [param objectForKey:@"serviceNumber"];
    NSString *phoneNumber = [param objectForKey:@"phoneNumber"];
    NSDictionary *externalParams = [param objectForKey:@"externalParams"];
    if ([[Utils chechNull:accountName] isEqualToString:@""]){
     failed(@"params accountName empty....");
     return;
    }
    if ([[Utils chechNull:serviceNumber] isEqualToString:@""]){
     failed(@"params serviceNumber empty....");
     return;
    }
    if ([[Utils chechNull:phoneNumber] isEqualToString:@""]){
     failed(@"params phoneNum empty....");
     return;
    }
    else{
     if (![Utils isNumber:[Utils chechNull:phoneNumber]]){
      failed(@"phoneNum must be number");
      return;
     }
    }
    self->initing = true;
    self.cId = [NSString stringWithFormat:@"%@-%@",[Utils generateUUIDString],[Utils currentDateStringWithFormat:@"yyyy-MM-dd HH:mm:ss"]];
    if (externalParams != nil){
     self.phoneStatus.params = [self createDefaultSipHeader:externalParams];
    }
    else {
     self.phoneStatus.params = [self createDefaultSipHeader:[NSDictionary new]];
    }
    self.phoneStatus.serviceCallMode = true;
    dispatch_async(dispatch_get_main_queue(), ^{
     [[Common new] goToCallInitView];
    });
    
    self.phoneStatus.phoneNum = serviceNumber;
    self.phoneStatus.fromNum = phoneNumber;
    
    [self initUrl:accountName urlBack:^(NSString *message) {
     
     NSString *url = message;
     if([[Utils readValueWithKey:[self getServiceUrlKey:serviceNumber]] isEqualToString:@""]){
      [Utils request1139WithSerNo:serviceNumber andUrl:url succ:^(NSString *sipServer) {
       [Utils saveValue:sipServer withKey:[self getServiceUrlKey:serviceNumber]];
       [self callServiceNumWithPbxUrl:sipServer];
      } failed:^(NSString * _Nonnull msg) {
       failed(@"request a6 sip info failed");
       [self initFailed];
      }];
     }
     else{
      [Utils request1139WithSerNo:serviceNumber andUrl:url succ:^(NSString *sipServer) {
       [Utils saveValue:sipServer withKey:[self getServiceUrlKey:serviceNumber]];
       
      } failed:^(NSString * _Nonnull msg) {
       
      }];
      NSString * sipServer = [Utils readValueWithKey:[self getServiceUrlKey:serviceNumber]];
      [self callServiceNumWithPbxUrl:sipServer];
      
     }
     
    } urlFail:^(NSString *message) {
     [self initFailed];
     self->fail(message);
    }];

   }
   else{
    failed(@"need auth");
   }
  }];
 }
 
}

-(void)initSuccess{
 self->initing = false;
 [[NSNotificationCenter defaultCenter] postNotificationName:InitStateChange object:InitSuccess];
}
-(void)initFailed{
 self->initing = false;
 [[NSNotificationCenter defaultCenter] postNotificationName:InitStateChange object:InitFailed];
}

@end
